package com.ontheroad.controller;

import cn.modoumama.page.GridDataModel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.ontheroad.core.util.GpxUtils;
import com.ontheroad.core.util.SpringSecurityUtils;
import com.ontheroad.core.web.BaseController;
import com.ontheroad.map.UserPathQuery;
import com.ontheroad.path.model.PathSystemModel;
import com.ontheroad.path.model.PathUserModel;
import com.ontheroad.path.model.PoiModel;
import com.ontheroad.path.model.Point;
import com.ontheroad.path.service.PathService;
import com.ontheroad.path.service.PathSysService;
import com.ontheroad.system.entity.GeoLogModel;
import com.ontheroad.system.service.GeologService;
import com.ontheroad.user.model.UserModel;
import com.ontheroad.user.service.UserService;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * Created by kedong on 2017/6/28 0028.
 */
@RequestMapping("map/")
@Controller
public class MapController extends BaseController {

    Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    private PathService pathService;
    @Autowired
    private PathSysService pathSysService;
    @Autowired
    private GeologService geologService;
    @Autowired
    private UserService userService;

    @RequestMapping("index")
    public String index(Map map) {
        map.put("userId", SpringSecurityUtils.getCurrentUser().getUserId());
        return "map/index";
    }

    @RequestMapping("save")
    @ResponseBody
    public Boolean saveLine(String geoJsonStr, String gpxStr, Boolean isPublish) {
        try {
            Integer userId = SpringSecurityUtils.getCurrentUser().getUserId().intValue();
            Gson gson = new Gson();

            List<String> gpxs = gson.fromJson(gpxStr, new TypeToken<List<String>>() {
            }.getType());

            JSONArray jsonArray = JSON.parseArray(geoJsonStr);
            if (jsonArray.size() > 0) {
                List<Point> points = new ArrayList<>();
                for (int i = jsonArray.size() - 1; i >= 0; i--) {
                    JSONObject json = jsonArray.getJSONObject(i);
                    JSONObject geometry = json.getJSONObject("geometry");
                    if (geometry != null) {
                        String type = (String) geometry.get("type");
                        switch (type) {
                            case "Point":
                                savePoint(json);
                                break;
                            case "Polygon":
                            case "MultiLineString":
                            case "LineString":
                                saveMultiLineString(json, gpxs.get(i), isPublish);
                                break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("保存地图要素失败：", e);
            return false;
        }
        return true;
    }

    /**
     * 保存轨迹
     *
     * @param json
     * @param gpx
     * @throws Exception
     */
    private void saveMultiLineString(JSONObject json, String gpx, Boolean isPublish) throws Exception {
        PathSystemModel systemModel = new PathSystemModel();
        Map<String, Object> map = (Map<String, Object>) json.get("properties");
        if (map != null) {
            BeanUtils.copyProperties(systemModel, map);
        }
        // 轨迹长度在页面上处理成了公里
        Double kilometre = systemModel.getKilometre() * 1000;
        systemModel.setKilometre(kilometre);

        systemModel.setIsPublish(isPublish);
        systemModel.setGpx(gpx);
        systemModel.setGeojson(json.toJSONString());
        Integer userId = SpringSecurityUtils.getCurrentUser().getUserId().intValue();
        systemModel.setCreateId(userId);
        systemModel.setCreateTime(new Date());
        PathSystemModel query = pathSysService.findByTimestamp(systemModel.getTimestamp());
        if (query == null) {
            // 保存轨迹
            systemModel = pathSysService.save(systemModel);
        } else {
            systemModel.setId(query.getId());
            pathSysService.updateById(systemModel);
            pathSysService.deleteSysPathPointByPathId(systemModel.getId());
        }
        // 轨迹点
        pathService.addPoint(gpx, null, null, systemModel.getId().intValue());
    }

    private void savePoint(JSONObject json) throws Exception {
        PoiModel poi = new PoiModel();
        Map<String, Object> map = (Map<String, Object>) json.get("properties");
        if (map != null) {
            BeanUtils.copyProperties(poi, map);
        }
//        {"geometry":{"coordinates":[114.27324700767257,30.46612104356645],"type":"Point"},"type":"Feature"}
        JSONObject geometry = json.getJSONObject("geometry");
        JSONArray coordinates = (JSONArray) geometry.get("coordinates");
        poi.setLng(coordinates.getDoubleValue(0));
        poi.setLat(coordinates.getDoubleValue(1));
        Integer userId = SpringSecurityUtils.getCurrentUser().getUserId().intValue();
        poi.setUserId(userId);
        poi.setCreateTime(new Date());
        // 保存POI点
        PoiModel query = pathSysService.findPoiByTimestamp(poi.getTimestamp());
        if (query == null) {
            pathSysService.savePoi(poi);
        } else {
            pathSysService.updatePoi(poi);
        }
    }

    @RequestMapping(value = "history", method = RequestMethod.POST)
    @ResponseBody
    public void saveHistory(GeoLogModel geoLogModel) {
        try {
            if (StringUtils.isNotEmpty(geoLogModel.getGeojson())) {
                Integer userId = SpringSecurityUtils.getCurrentUser().getUserId().intValue();
                Map<String, Object> map = new HashMap<>();
                map.put("userId", userId);
                List<GeoLogModel> list = geologService.findModelsByCondition(map);
                if (list != null && list.size() > 0) {
                    GeoLogModel tmp = list.get(0);
                    geoLogModel.setId(tmp.getId());
                    geoLogModel.setAdminId(userId);
                    geoLogModel.setCreateTime(new Date());
                    geologService.updateById(geoLogModel);
                } else {
                    geologService.insert(geoLogModel);
                }
            }
        } catch (Exception e) {
            log.error("保存历史记录失败", e);
        }
    }

    @RequestMapping(value = "history", method = RequestMethod.DELETE)
    @ResponseBody
    public void deleteHistory() {
        try {
            Integer userId = SpringSecurityUtils.getCurrentUser().getUserId().intValue();
            geologService.deleteByUserId(userId);
        } catch (Exception e) {
            log.error("删除历史记录失败", e);
        }
    }


    @RequestMapping(value = "history", method = RequestMethod.GET)
    @ResponseBody
    public List<GeoLogModel> getHistory() {
        try {
            Integer userId = SpringSecurityUtils.getCurrentUser().getUserId().intValue();
            Map<String, Object> map = new HashMap<>();
            map.put("userId", userId);
            return geologService.findModelsByCondition(map);
        } catch (Exception e) {
            log.error("保存历史记录失败", e);
        }
        return null;
    }

    @RequestMapping("getUserPath")
    @ResponseBody
    public GridDataModel getUserPath(HttpServletRequest request) throws Exception {
        GridDataModel gridDataModel = getGridData(request, pathService);
        List<PathUserModel> pathUserModels = (List<PathUserModel>) gridDataModel.getRows();
        pathUserModels = createGpx(pathUserModels);
        gridDataModel.setRows(pathUserModels);
        return gridDataModel;
    }

    @RequestMapping("getSysPath")
    @ResponseBody
    public GridDataModel getSysPath(HttpServletRequest request) {
        return getGridData(request, pathSysService);
    }

    /**
     * 搜索用户轨迹
     *
     * @param userPathQuery
     * @return
     */
    @RequestMapping(value = "searchUser")
    @ResponseBody
    public List<PathUserModel> search(UserPathQuery userPathQuery) {
        Integer type = userPathQuery.getType();
        List<PathUserModel> list = new ArrayList<>();
        switch (type) {
            case 1:
                // 通过点搜索附近的轨迹
                list = pathService.findNearPath(userPathQuery.getLat(), userPathQuery.getLng());
                break;
            case 2:
                // 通过名称搜索
                Map<String, Object> map = new HashMap<>();
                if (StringUtils.isNotEmpty(userPathQuery.getMobile())) {
                    map.put("mobileLike", userPathQuery.getMobile());
                }
                if (StringUtils.isNotEmpty(userPathQuery.getPhoneModel())) {
                    map.put("phomeModel", userPathQuery.getPhoneModel());
                }
                if (StringUtils.isNotEmpty(userPathQuery.getCity())) {
                    map.put("address", userPathQuery.getCity());
                }
                if (null != userPathQuery.getSystemType()) {
                    map.put("systemType", userPathQuery.getSystemType());
                }
                List<Integer> userIds = null;
                if (map.size() > 0) {
                    List<UserModel> users = userService.findModelsByCondition(map);
                    if (users != null && users.size() > 0) {
                        Set<Integer> ids = new HashSet<>();
                        for (UserModel user : users) {
                            ids.add(user.getId());
                        }
                        userIds = new ArrayList<>(ids);
                    } else {
                        return list;
                    }
                }

                map.clear();
                map.put("startTime", userPathQuery.getStartTime());
                map.put("endTime", userPathQuery.getEndTime());
                if (userIds != null && userIds.size() > 0) {
                    map.put("userIds", userIds);
                }
                list = pathService.findModelsByCondition(map);
                break;
        }
        list = createGpx(list);
        return list;
    }

    /**
     * 搜索系统轨迹
     *
     * @param type 1、通过点
     * @return
     */
    @RequestMapping("searchSysPath")
    @ResponseBody
    public List<PathSystemModel> searchSysPath(Integer type, @RequestParam(required = false) String name,
                                               @RequestParam(required = false) Double lat, @RequestParam(required = false) Double lng) {
        switch (type) {
            case 1:
                // 通过点搜索附近的轨迹
                return pathSysService.findNearPath(lat, lng);
            case 2:
                // 通过名称搜索

                break;
        }
        return null;
    }


    private List<PathUserModel> createGpx(List<PathUserModel> pathUserModels) {
        try {
            if (pathUserModels != null && pathUserModels.size() > 0) {
                for (PathUserModel pathUserModel : pathUserModels) {
                    String gpx = pathUserModel.getGpx();
                    if (StringUtils.isEmpty(gpx)) {
                        List<Point> points = pathService.findPointsByPathUserId(pathUserModel.getId());
                        gpx = GpxUtils.getGpx(points);
                        pathUserModel.setGpx(gpx);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("将坐标转换成gpx失败:", e);
        } finally {
            return pathUserModels;
        }
    }

    @RequestMapping("deleteSysPath")
    @ResponseBody
    public Boolean deleteSysPath(Long id) {
        try {
            pathSysService.removeById(id);
            return true;
        } catch (Exception e) {
            log.error("删除系统轨迹失败", e);
            return false;
        }
    }
}
